<?php

namespace CoffeeScript;

class yy_If extends yy_Base
{

    public $children = array('condition', 'body', 'else_body');

    function constructor($condition, $body, $options = array())
    {
        $this->condition = (isset($options['type']) && $options['type'] === 'unless') ? $condition->invert() : $condition;
        $this->body = $body;
        $this->else_body = NULL;
        $this->is_chain = FALSE;
        $this->soak = isset($options['soak']) ? $options['soak'] : NULL;

        return $this;
    }

    function add_else($else_body)
    {
        if ($this->is_chain()) {
            $this->else_body_node()->add_else($else_body);
        } else {
            $this->is_chain = $else_body instanceof yy_If;
            $this->else_body = $this->ensure_block($else_body);
        }

        return $this;
    }

    function body_node()
    {
        return $this->body ? $this->body->unwrap() : NULL;
    }

    function compile_node($options = array())
    {
        return $this->is_statement($options) ? $this->compile_statement($options) : $this->compile_expression($options);
    }

    function compile_expression($options)
    {
        $cond = $this->condition->compile($options, LEVEL_COND);
        $body = $this->body_node()->compile($options, LEVEL_LIST);

        $alt = ($tmp = $this->else_body_node()) ? $tmp->compile($options, LEVEL_LIST) : 'void 0';
        $code = "{$cond} ? {$body} : {$alt}";

        return (isset($options['level']) && $options['level'] >= LEVEL_COND) ? "({$code})" : $code;
    }

    function compile_statement($options)
    {
        $child = del($options, 'chainChild');
        $exeq = del($options, 'isExistentialEquals');

        if ($exeq) {
            return yy('If', $this->condition->invert(), $this->else_body_node(), array('type' => 'if'))->compile($options);
        }

        $cond = $this->condition->compile($options, LEVEL_PAREN);
        $options['indent'] .= TAB;
        $body = $this->ensure_block($this->body);
        $if_part = "if ({$cond}) {\n" . $body->compile($options) . "\n{$this->tab}}";

        if (!$child) {
            $if_part = $this->tab . $if_part;
        }

        if (!$this->else_body) {
            return $if_part;
        }

        $ret = $if_part . ' else ';

        if ($this->is_chain()) {
            $options['indent'] = $this->tab;
            $options['chainChild'] = TRUE;

            $ret .= $this->else_body->unwrap()->compile($options, LEVEL_TOP);
        } else {
            $ret .= "{\n" . $this->else_body->compile($options, LEVEL_TOP) . "\n{$this->tab}}";
        }

        return $ret;
    }

    function else_body_node()
    {
        return (isset($this->else_body) && $this->else_body) ? $this->else_body->unwrap() : NULL;
    }

    function ensure_block($node)
    {
        return $node instanceof yy_Block ? $node : yy('Block', array($node));
    }

    function is_chain()
    {
        return $this->is_chain;
    }

    function is_statement($options = array())
    {
        return (isset($options['level']) && $options['level'] === LEVEL_TOP) ||
                $this->body_node()->is_statement($options) ||
                (($tmp = $this->else_body_node()) && $tmp->is_statement($options));
    }

    function jumps($options = array())
    {
        $tmp = $this->body->jumps($options);

        if (!$tmp && isset($this->else_body)) {
            $tmp = $this->else_body->jumps($options);
        }

        return $tmp;
    }

    function make_return($res = NULL)
    {
        if (!(isset($this->else_body) && $this->else_body)) {
            if ($res) {
                $this->else_body = yy('Block', array(yy('Literal', 'void 0')));
            }
        }

        if ($this->body) {
            $this->body = yy('Block', array($this->body->make_return($res)));
        }

        if ($this->else_body) {
            $this->else_body = yy('Block', array($this->else_body->make_return($res)));
        }

        return $this;
    }

    function unfold_soak($options = NULL)
    {
        return $this->soak ? $this : FALSE;
    }

}

?>
